 
package linuxbox.util;

import java.io.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;

import linuxbox.BoxStatic;
/**
 * The FileServlet is capable of handling browser based HTTP requests
 * for uploading and download files.
 * 
 * Upload
 * 
 * The FileServlet is capable of handling more than one file per
 * upload request.  The upload request is handled by the
 * processFileUploadRequest method.  This method reads the uploaded
 * file into a byte array.  Note that this class is abstract. It is
 * the responsibility of the subclass to provide the action after the file
 * contents are available in the byte array.  The abstract method
 * processFile(filename, byteArray, contentType) should be
 * implemented by the subclass to achieve this.
 * 
 * The browser can upload multiple files at the same time. For each such file
 * read, this class calls the processFile() method exactly once.
 * 
 * Subclasses can be written to implement the following possible
 * functionalities :
 * 
 * Write the contents of the byte[] to a local file
 * Send the byte[] as a file attachment by email
 * FTP the byte[] as a file to a FTP server
 * Pass the byte[] to an EJB
 * 
 * and many more.
 * 
 * The code below demonstrates the first example, namely saving the contents
 * of the byte[] to a local file.
 *  
 * // TestUploadServlet.java
 * public class TestUploadServlet extends FileServlet
 * {
 *   protected void processFile(String fileName,
 *                              byte content[], 
 *                              String contentType)
 *   {
 *       try
 *       {
 *         FileOutputStream fos = new FileOutputStream(new File(fileName));
 *         fos.write(content);
 *         fos.flush();
 *         fos.close();
 *       }
 *       catch(Exception e)
 *       {
 *         e.printStackTrace();
 *       } 
 *   }
 * } // TestUploadServlet
 * 
 * 
 * This TestUploadServlet extends FileServlet and
 * implements the processFile method.  The rest of the methods such
 * as (init(), doGet(), doPost(), ...) etc are
 * derived from FileServlet. The default implemetation of these
 * methods can be overridden if necessary. The TestUploadServlet
 * writes the file to the current directory.
 * 
 * A client can upload files using an HTML form with the following structure.
 * 
 * <FORM ACTION="/servlet/YourServlet" METHOD=POST
 *   ENCTYPE="multipart/form-data">
 * Which file to upload? <INPUT TYPE="FILE" NAME="file">
 * <INPUT TYPE="SUBMIT">
 * </FORM>
 * 
 * Note :
 * 
 * Not all browsers support file uploads.
 * The HTML form can have more than one input field of type 'file'.  
 * 
 * 
 * Download
 * 
 * The download request is handled by the processFileDownloadRequest(
 * HttpServletRequest request, HttpServletResponse reply, byte content[],
 * String contentType) method, where the content[] is the file
 * content. This method sets the response's content type  to the specified
 * content type and writes the byte[] to the servlets output stream. 
 * 
 * What should I do to use the File Servlet
 * 
 * Upload
 * 
 * Write a Servlet class extending from FileServlet
 * Implement the <tt>processFile() method
 * Override the dispatchMessage() method to display customized
 * message
 * 
 * Download
 * 
 * Write a Servlet class extending from FileServlet
 * Implement code that takes care of reading the file to be downloaded
 *     from the required source and store it in a byte[].
 * Get the mime type of the file
 * Call the processFileDownloadRequest() of the
 *     FileServlet with appropriate parameters. 
 * 
 * 
 */
abstract public class FileServlet extends HttpServlet {
	/**
	 * Initializes the servlet.
	 */
	public void init(ServletConfig config) throws ServletException {
		super.init(config);
	}
	
	/**
	 * Handle GET request
	 */
	public final void doGet(HttpServletRequest request, 
	HttpServletResponse reply) throws IOException {
		// Call process Request
		processRequest(request, reply);
	}
	
	/**
	 * Handle POST request
	 */
	public final void doPost(HttpServletRequest request, 
	HttpServletResponse reply) throws IOException {
		// Call process Request
		BoxStatic.logger.debug("I am in doPost - FileServlet");
		processRequest(request, reply);
	}
    
	/**
	 * Method Process Request, by default will pass control to the 
	 * processFileUploadRequest() method. 
	 *
	 * @param session  HttpSession
	 * @param request  HttpServletRequest
	 * @param reply    HttpServletResponse
	 */
	public void processRequest(HttpServletRequest request,
	HttpServletResponse reply) throws IOException {
		debug("IN PROCESS REQUEST FILE SERVELT");
		//processFileUploadRequest(request, reply, ".");
		processFileUploadRequest(request, reply);
	}

	/**
	* Handles file upload request.
	*
	* @param request  HttpServletRequest
	* @param response HttpServletResponse
	*
	*/
	protected void processFileUploadRequest(HttpServletRequest request, 
	HttpServletResponse reply, String saveDir) throws IOException {
		debug("######### IN PROCESS FILE UPLOAD ##########");
	
		MultipartRequest multi = null;
	
		// Variable to hold the file name
		String filename = "";
	
		// Create an instance of the MultipartRequest
		if (saveDir != null && saveDir.length() > 0)
			multi = new MultipartRequest(request, saveDir);
		else
			multi = new MultipartRequest(request, ".");
	
		// Get the list of files to be uploaded
		Enumeration files = multi.getFileNames();
	
		// Loop for all files
		while (files.hasMoreElements()) {
			// Get the name of the file
			String name = (String)files.nextElement();
	
			// Get the file system name of the file
			filename = multi.getFilesystemName(name);
			debug("FILENAME: " + filename);
	
			// Get File
			File f = multi.getFile(name);
	
			// Get content type of this file 
			String contentType = multi.getContentType(name);
	
			// create a byte array 
			FileInputStream inp = new FileInputStream(f);
			byte[] cont = new byte[(int) f.length()];
	
			// read from the input stream
			inp.read(cont);
	
			// call the processFile method
			processFile(filename, cont, contentType);
	
			// Close the input Stream
			inp.close();
		}
	
		// Dispatch Message
		dispatchMessage(request, reply, 0); // Sucessful
	}    

	/**
	* Handles file upload request.
	*
	* @param request  HttpServletRequest
	* @param response HttpServletResponse
	*
	*/
	protected void processFileUploadRequest(HttpServletRequest request, 
	HttpServletResponse reply) throws IOException {
		debug("######### IN PROCESS FILE UPLOAD ##########");
	
		MultipartRequest multi = null;
	
		// Variable to hold the file name
		String filename = "";

		multi = new MultipartRequest(request, ".");
	
		// Get the list of files to be uploaded
		Enumeration files = multi.getFileNames();
	
		// Loop for all files
		while (files.hasMoreElements()) {
			// Get the name of the file
			String name = (String)files.nextElement();
	
			// Get the file system name of the file
			filename = multi.getFilesystemName(name);
			debug("FILENAME: " + filename);
	
			// Get File
			File f = multi.getFile(name);
	
			// Get content type of this file 
			String contentType = multi.getContentType(name);
	
			// create a byte array 
			FileInputStream inp = new FileInputStream(f);
			byte[] cont = new byte[(int) f.length()];
	
			// read from the input stream
			inp.read(cont);
	
			// call the processFile method
			processFile(filename, cont, contentType);
	
			// Close the input Stream
			inp.close();
		}
	
		// Dispatch Message
		dispatchMessage(request, reply, 0); // Sucessful
	}    
    
	/**
	 * Handles file download request.
	 *
	 * @param request  HttpServletRequest
	 * @param response HttpServletResponse
	 */
	protected void processFileDownloadRequest(HttpServletRequest request, 
	HttpServletResponse reply, byte content[], String contentType) 
	throws ServletException, IOException {
		debug("######### IN PROCESS FILE DOWNLOAD ##########");
		DataOutputStream dos = null;
		
		try {
			reply.setContentType(contentType);
			reply.setContentLength(content.length);
			dos =  new DataOutputStream(reply.getOutputStream());
			dos.write(content);
			dos.flush();
		} finally {
			if (dos!=null)
			dos.close();
		} 
	}    

	/**
	 * This method is responsible for handling the uploaded file. This is an
	 * abstract method and the definition has to be implemented in the
	 * subclass.
	 *
	 * @param fileName   name of the uploaded file
	 * @param content    contents of the uploaded file as byte array
	 * @param contentType content type of the uploaded file 
	 */
	abstract protected void processFile(String fileName,
	byte content[], String contentType);
   
	/**
	 * Method to dispatch message after the file is uploaded.
	 *
	 * @param request  HttpServletRequest
	 * @param response HttpServletResponse
	 * @param status  -1 - Error Uploading the file
	 *                 0 - Upload Sucessful
	 */
	protected void dispatchMessage(HttpServletRequest request, 
	HttpServletResponse reply, int status) throws IOException {
		String message = "Upload Sucessful";
		PrintWriter out = reply.getWriter();
		if (status == -1)
			message = "Error Uploading the File";
		out.println("<HTML><BODY><h3>" + message + "</h3></body></html>");
	}

	private void debug(String msg) {
		BoxStatic.logger.debug(msg);
	}
} // FileServlet
